--==============================--
--desc: 
-- 创建类:
-- Player = class("Player", super)
-- super可以是表或者函数, 也可以是类
-- 类内容: class {classname="Player", super={}, new=构造函数, __create=特殊创建实例函数}
-- 创建实例:
-- local player = Player.new(...) 创建实例
-- 实例内容: player {class=类, 元表引用类的所有内容}
-- 创建的对象不是table, 实现复制功能(可能会报错)
--time:2018-01-20 10:34:32
--==============================--
-- 遍历构造对象
local function ctor_obj(c, obj, copy, ...)
	if c.super then
		-- 父类构造函数
		ctor_obj(c.super, obj, copy, ...)
	end
	
	-- 是否复制构造
	if copy then
		-- 遍历赋值
		for k, v in pairs(c) do
			-- 过滤
			if not(k == "__create" or k == "classname" or k == "new") then
				obj[k] = v -- 复制
			end
		end
		-- class 赋值
		obj["class"] = c
	end
	
	-- 构造函数
	if c.ctor then
		c.ctor(obj, ...)
	end
end

-- 创建类对象
local function new(class, ...)
	-- log.debug("class.new : ", ...)
	-- create
	local instance = class.__create and class.__create(...) or {}
	
	-- check
	local obj_type = type(instance)
	local ctor_copy = false
	if obj_type ~= "table" then
		-- error("create instance mush table! instance type:" .. obj_type)
		ctor_copy = true -- 非table, 无法用元表, 只能复制
	end
	-- ctor_copy = true -- 测试复制功能
	-- ctor
	ctor_obj(class, instance, ctor_copy, ...)
	
	-- not copy to setmetatable
	if not ctor_copy then
		-- 绑定元表
		setmetatable(instance, {__index = function(t, k)
			if k == "class" then
				return class
			end
			return class[k]
		end})
	end
	return instance
end

-- 新建类(类名, 父类)
function class(classname, super)
	-- 创建类
	local class = {}
	class.classname = classname			-- 函数名
	
	--新建对象(类, 对象)
	class.new = function(...) return new(class, ...) end
	
	-- 处理是否继承
	if super then
		if type(super) == "function" then
			-- 创建函数
			class.__create = super
		else
			-- 绑定父类
			setmetatable(class, {__index = super})
			class.super = super -- 父类
		end
	end
	-- print("class:", table.tostring(class), " super:", table.tostring(class.super))
	return class
end

--是否继承与(对象, 类)
function instanceof(obj, class)
	local obj_class = obj.class
	while obj_class ~= nil do
		--check class
		if obj_class == class then
			return true
		end
		--next
		obj_class = obj_class.super
		-- print("index", index)
	end
	return false
end

--获取类名
function classname(obj)
	return obj.class and obj.class.classname or nil
end

-- 获取对象类
function objclass(obj)
	return obj.class
end

-- -- 元表测试
-- local a = {a = 1, b = 2, c = 3}
-- local b = {}
-- setmetatable(b, a)
-- print("test 1", b.a, b.b)
-- local c = {__index = a}
-- print("test 2", c.a, c.b)
-- local d = {__index = function(t, k) return 1 end}
-- print("test 3", d.a, d.b)
-- local b1 = {}
-- setmetatable(b1, {__index = a})
-- print("test 11", b1.a)
-- local e = {}
-- local function new_index(t, k, v)
-- 	print("new index:", t, k, v)
-- 	e[k] = v
-- end
-- local f = {__newindex = new_index}
-- setmetatable(f, {__index = e})
-- f.a = 1
-- print("test 4 ", f.a)
-- local g = {}
-- local i = setmetatable(g, {__index = e, __newindex = e})
-- g.a = 1
-- print("test 5 ", g, i, g.a, e.a)
------------------- table to string, 类和带函数的对象如果需要显示, 请用table.tostring---------------------------
-- if not table.tostring then
-- 	-- tostring func
-- 	function table.tostring(t)	
-- 		if type(t) ~= "table" then
-- 			return tostring(t)
-- 		end
-- 		local index = 0
-- 		local str = "{"
-- 		for k, v in pairs(t) do
-- 			index = index + 1
-- 			if index > 1 then
-- 				str = str .. ","
-- 			end
-- 			str = str .. "\'" .. tostring(k) .. "\':\'" .. table.tostring(v) .. "\'"
-- 		end
-- 		str = str .. "}"
-- 		return str
-- 	end
-- end
-- ---------------------test--------------------
-- local ClassA = class("ClassA")
-- ClassA.b = 2
-- ClassA.c = 2
-- function ClassA:test()
-- 	print("class a test")
-- end
-- local ClassB = class("ClassB", {})
-- local ClassC = class("ClassC", ClassB)
-- local ClassD = class("ClassD", function()
-- 	return {k = 3}
-- end)
-- local ClassE = class("ClassE", ClassD)
-- local objA = ClassA.new()
-- objA.a = 2
-- objA.b = 3
-- local objB = ClassB.new()
-- local objC = ClassC.new()
-- local objD = ClassD.new()
-- local objE = ClassE.new()
-- print("objA:", table.tostring(objA), objA.a, objA.b, objA.c, objA.test)
-- print("objB:", table.tostring(objB))
-- print("objC:", table.tostring(objC))
-- print("objD:", table.tostring(objD))
-- print("objE:", table.tostring(objE))
-- print("test: ", ClassA.classname, assert(ClassA.classname == "ClassA"))
-- print("test: ", ClassB.classname, assert(ClassB.classname == "ClassB"))
-- print("test: ", ClassC.classname, assert(ClassC.classname == "ClassC"))
-- print("test: ", ClassD.classname, assert(ClassD.classname == "ClassD"))
-- print("test: ", ClassE.classname, assert(ClassE.classname == "ClassE"))
-- print("obj a: ", "class=", classname(objA), assert(classname(objA) == "ClassA"))
-- print("obj b: ", "class=", classname(objB), assert(classname(objB) == "ClassB"))
-- print("obj d: ", "class=", classname(objD), assert(classname(objC) == "ClassC"))
-- print("obj e: ", "class=", classname(objE), assert(classname(objD) == "ClassD"))
-- print("obj: a is classB", instanceof(objA, ClassB), assert(not instanceof(objA, ClassB)))
-- print("obj: b is classB", instanceof(objB, ClassB), assert(instanceof(objB, ClassB)))
-- print("obj: c is classB", instanceof(objC, ClassB), assert(instanceof(objC, ClassB)))
-- print("obj: b is classC", instanceof(objB, ClassC), assert(not instanceof(objB, ClassC)))
-- print("obj: d is classD", instanceof(objD, ClassD), assert(instanceof(objD, ClassD)))
-- print("obj: e is classD", instanceof(objE, ClassD), assert(instanceof(objE, ClassD)))
